Jenkins, la nouvelle génération

NightClazz Lille - 4 Décembre 2017

Damien DUPORTAL & Jean-Marc MEESSEN

Qui a connu ceci ?

Nostalgie 1

Ou encore ceci ?

Nostalgie 2

Et puis…​

Nostalgie 3

Bonjour !

Damien DUPORTAL

damien

Jean-Marc MEESSEN

Jmm
fishSticks
Presentation CloudBees

Et vous ?

commitstrip
  • Y a-t-il des développeurs ici ?

  • Qui pratique l’Intégration Continue ?

  • Avec quels outils ?

    • Jenkins "Old School" ? / "New Generation" ?

    • GitLab ? TeamCity ? TravisCI ? Bamboo ?

    • Autre ?

Objectifs

Objectifs

  • Présentation générale

    • Jenkins Pipelines

    • Blue Ocean

  • Donner des pistes d’exploration

  • Mais c’est mieux avec un atelier (Lab)

Rappels

Continuous Integration

fail fast continuous integration
  • Chaque intégration est validée par un build automatisé (avec tests)

  • Le code est intégré souvent, au moins journellement, pour que l’intégration soit un non-event

  • Construire et intégrer le code en continu, avec une boucle de feedback

DevOps: Software as a "Supply Chain"

supply chain
CD and CD

The Pipeline

pipeline

Jenkins

jenkins logo
  • Logiciel Open Source

  • Orchestrateur de tâches

  • Un des tout premiers moteur d’intégration continue

  • Architecture centrée sur les plugins

    • Un gigantesque écosystème

BlueOcean

Blue Ocean

  • Pierre angulaire de l’évolution de Jenkins

  • Visualisation et manipulation de "Pipelines"

  • GUI moderne, se concentrant sur les actions principales

Jenkins Pipelines

  • Un outil pour définir votre flux de Continuous Delivery/Deployment avec votre code

  • != outil de création de job comme "Job DSL"

Ses avantages:

  • Réduit le nombre de jobs nécessaires

  • Spécification facilitée par du "code"

  • Survi au redémarrage du Jenkins Master

Définition

  • Le Pipeline est décrit dans un fichier texte: le JenkinsFile

    • DSL spécifique

    • stocké dans un SCM

      • versionné

      • isolation par branche

      • suit les patterns à la “Git / Github / Gitlab flow”

Débuter avec les Pipelines

Declarative or Scripted Pipelines ?

  • Declarative

    • Syntaxe par défaut

    • S’utilise avec Blue Ocean

  • Scripted

    • Syntaxe originale (~3 ans)

    • "Great Power == Great Responsibility"

    • À utiliser lorsque le Déclaratif commence à être bizarre

Blue Ocean Pipeline Editor

  • Fourni le cycle ("round trip") complet avec le SCM

  • Pas de Pipeline ? "Suivez le guide".

  • Le Pipeline existe déjà ? Edit, commit, et exécutez le

Simple Pipeline

Accessing your Lab Instance

  • Get the AWS DNS name of your machine

  • Open the URL YOUR_INSTANCE_DNS:10000

    • Welcome to the Lab Home Page

  • Click the link Workshop Slides

    • Browse to this current slide

Accessing Source Code

Accessing Jenkins

Blue Ocean

Exercise: Create First Project

  • Create a new Pipeline, with the following properties:

    • Stored in Git

    • Get the SSH URL from the git server

    • Configure Jenkins access to the source code:

      • In Gitea, click the top-right user drop down

      • Browse to SSH/GPG Keys

      • Add a new key, by copy and pasting from Jenkins

Exercise - Your First Pipeline

  • Click the button Create a Pipeline

  • Use the Blue Ocean Pipeline Editor and Gitea git server

  • Create a Pipeline that have 3 stages: Build, Test and Deploy

  • Each stage has 1 step that prints a message

    • "Building…​" for Build, "Testing…​" for Test…​

  • Save, add a commit message and see the build kicking off

Solution - Your first pipeline

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        echo 'Build'
      }
    }
    stage('Test') {
      steps {
        echo 'Test'
      }
    }
    stage('Deploy') {
      steps {
        echo 'Deploy'
      }
    }
  }
}

Exercise - Run tasks with Pipeline

  • Using the Blue Ocean Pipeline Editor:

    • Edit the current Pipeline’s 3 stages to run scripts

    • Scripts are stored in the ./scripts folder (in SCM)

    • Use the step Shell Script (keyword sh)

    • Remove the echo steps

  • Save, add a commit message and see the build kicking off

Solution - Run tasks with Pipeline

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh './scripts/build.sh'
      }
    }
    stage('Test') {
      steps {
        sh './scripts/test.sh'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Exercise - Archives and Tests

  • Using the Blue Ocean Pipeline Editor:

    • Edit the current Pipeline

    • Build stage should archive all *.jar files found in ./target

    • Test stage should publish the junit test reports

      • Found in ./target. TIP for recusrive: */.xml

  • Save, add a commit message and see the build kicking off

  • Build should be UNSTABLE

Solution - Archives and Tests

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh './scripts/build.sh'
        archiveArtifacts 'target/*.jar'
      }
    }
    stage('Test') {
      steps {
        sh './scripts/test.sh'
        junit 'target/**/*.xml'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Pipeline: Basiques

Exercise: Réparer le build

  • Le build est en état UNSTABLE (jaune)

  • Priorité: réparer le build

  • Utiliser Gitea git server

  • Les tests d’intégration sont dans src/tests/java/hello

  • Indices:

    • Integration Tests: == IT

    • Il suffit de savoir commenter/dé-commenter

Solution: Réparer le build

  • Depuis src/test/java/hello/HelloControllerIT.java

    • Cliquer sur "Edit"

  • Commenter la ligne 39

  • -commenter la ligne 40

  • Commit avec un message (push automatique)

  • Lancer le build manuellement dans Blue Ocean

  • Le build doit être vert (Stable)

Webhooks pour un retour plus rapide

  • Nous avons dû lancer le build manuellement

  • IC: Retours rapides !

    • Lancer le build dès que le code est poussé

Exercise: Webhooks

Solution: Webhooks

  • Ajoutez un commentaire dans le Jenkinsfile depuis Gitea git server

    • Un build va démarrer

    • Validez dans l’onglet "Changes"

Aller plus loin…​

  • Dans l’éditeur Blue Ocean, voir la version textuelle:

    • Combinaison CTRL + S (On Mac: CMD +S)

    • Bi-directionnel: essayez de charger une solution de pipeline

  • Le Pipeline Syntax Snippet Generator comme acolyte:

Exercise - Réutilisation Binaire

  • But: réutiliser les binaires générés dans Build

  • Action: "mise sur étagère": Stash / Unstash

  • Modifier le Pipeline pour :

    • "Stasher" le dossier target, à la fin de la phase Build

    • "Unstasher" au début de la phase Test

  • Attention, une limite de l’éditeur Blue Ocean va être atteinte

Solution - Réutilisation Binaire

  • L’éditeur Blue Ocean ne supporte pas encore le ré-ordonnancement de "stages"

    • Mode textuel et/ou Snippet Generator à utiliser

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh './scripts/build.sh'
        archiveArtifacts 'target/*.jar'
        stash(name: 'build-result', includes: 'target/**/*')
      }
    }
    stage('Test') {
      steps {
        unstash 'build-result'
        sh './scripts/test.sh'
        junit 'target/**/*.xml'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Post-Stage

  • Section post :

    • Contient des "steps" à exécuter à la fin du Pipeline ou après une "stage"

    • Divisé en "condition d’états": always, success, failure, changed

  • Chaque condition contient ses propres "steps"

  • Pas encore intégré dans l’éditeur Blue Ocean

Exercice - Rapport de Tests Unitaires

  • Si le "stage" Build échoue, alors la tâche "archiveArtifacts" ne devrait pas être exécutée

    • Même chose pour stash

  • Le rapports de tests unitaires doivent être publiés dans tous les cas

    • Format Junit

    • Stockés dans ./target/surefire-reports/*/.xml

  • Utiliser la documentation:

Solution - Rapport de Tests Unitaires

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh './scripts/build.sh'
      }
      post {
        always {
          junit 'target/surefire-reports/**/*.xml'
        }
        success {
          archiveArtifacts 'target/*.jar'
          stash(name: 'build-result', includes: 'target/**/*')
        }
      }
    }
    stage('Test') {
      steps {
        unstash 'build-result'
        sh './scripts/test.sh'
        junit 'target/**/*.xml'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Agents

Qu’est ce qu’un Agent?

  • Un noeud (ou node) est une machine prête à recevoir des builds

  • Step agent spécifie sur quel "noeud" exécuter des "stages".

  • Une section agent globale doit être définie (au niveau du block pipeline)

  • On peut aussi définire des sections agent par "stage"

Exercice - Agents

  • Exécuter l’étape Build sur un agent configuré avec le label maven-jdk8

  • Exécuter l’étape Test sur un agent configuré avec le label java8

  • L’éditeur Blue Ocean est utilisable

Solution - Agents

pipeline {
  agent any
  stages {
    stage('Build') {
      agent {
        node {
          label 'maven-java8'
        }
      }
      steps {
        sh './scripts/build.sh'
      }
      post {
        always {
          junit 'target/surefire-reports/**/*.xml'
        }
        success {
          archiveArtifacts 'target/*.jar'
          stash(name: 'build-result', includes: 'target/**/*')
        }
      }
    }
    stage('Test') {
      agent {
        node {
          label 'java8'
        }
      }
      steps {
        unstash 'build-result'
        sh './scripts/test.sh'
        junit 'target/**/*.xml'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Exercice - Tests Parallèles

  • But: Tester en parallèle l’application sur java 7 et 8

  • Mot clef parallel définissant un block contenant des "stages"

  • Agent java7 pour le Test Java 7

  • L’éditeur Blue Ocean est utilisable (et recommandé)

Solution - Tests Parallèles

pipeline {
  agent any
  stages {
    stage('Build') {
      agent {
        node {
          label 'maven-java8'
        }
      }
      steps {
        sh './scripts/build.sh'
      }
      post {
        always {
          junit 'target/surefire-reports/**/*.xml'
        }
        success {
          archiveArtifacts 'target/*.jar'
          stash(name: 'build-result', includes: 'target/**/*')
        }
      }
    }
    stage('Test') {
      parallel {
        stage('Test Java 8') {
          agent {
            node {
              label 'java8'
            }
          }
          steps {
            unstash 'build-result'
            sh './scripts/test.sh'
            junit 'target/**/*.xml'
          }
        }
        stage('Test Java 7') {
          agent {
            node {
              label 'java7'
            }
          }
          steps {
            unstash 'build-result'
            sh './scripts/test.sh'
            junit 'target/**/*.xml'
          }
        }
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Agents avec Docker

  • But: Usage de Docker pour faciliter la définition des environements de build

  • Le mot clef agent permet d’exécuter les "stages" dans un container Docker, depuis une "image Docker", ou depuis un Dockerfile (recette maison d’image Docker)

Exercice - Agent Docker

  • Exécuter le Build dans un containeur basé sur le fichier Dockerfile.build

  • Exécuter le Test Java 8 dans un containeur basé sur les images maven:3-jdk-8-alpine

  • Trick: documentation manquante sur filename, dans un block dockerfile

Solution - Agent Docker

pipeline {
  agent any
  stages {
    stage('Build') {
      agent {
        dockerfile {
          filename 'Dockerfile.build'
          label 'docker'
        }
      }
      steps {
        sh './scripts/build.sh'
      }
      post {
        always {
          junit 'target/surefire-reports/**/*.xml'
        }
        success {
          archiveArtifacts 'target/*.jar'
          stash(name: 'build-result', includes: 'target/**/*')
        }
      }
    }
    stage('Test') {
      parallel {
        stage('Test Java 8') {
          agent {
            docker {
              image 'maven:3-jdk-8-alpine'
              label 'docker'
            }
          }
          steps {
            unstash 'build-result'
            sh './scripts/test.sh'
            junit 'target/**/*.xml'
          }
        }
        stage('Test Java 7') {
          agent {
            node {
              label 'java7'
            }
          }
          steps {
            unstash 'build-result'
            sh './scripts/test.sh'
            junit 'target/**/*.xml'
          }
        }
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
      }
    }
  }
}

Pipeline Avancés

Input

  • Jenkins permet de "mettre en pause" l’exécution d’un pipeline, en attendant une validation humaine

    • For example, after the build and tests run successfully, you may want a human to confirm that the software should be deployed

What is Interactive Input? (2/2)

  • Implemented as a step, usually within its own stage

  • The input step should run on agent none; it must execute without an agent context and its associated workspace

  • Add the parameter for additional notes and echo the value.

  • In most cases, you want to define specific people who can approve moving forward

Exercice - Validation Humaine

Solution - Validation Humaine

Conditionnal Stage

Variables d’environment

Exercice - Déploiement Conditionnel

Solution - Déploiement Conditionnel